/*
    服务端数据管理模块：
    1、管理的数据消息
    • ⽂件实际存储路径
    • ⽂件是否压缩标志
    • 压缩包存储路径
    • ⽂件访问URL
    • ⽂件最后⼀次修改时间
    • ⽂件最后⼀次访问时间
    • ⽂件⼤⼩
    2、数据管理实现 -- 管理方式
        FileUtil 文件操作对象
        _table 一张实际文件存储url ： 管理数据信息
        _rwlock 读写锁  读不加锁 写需要
        InitLoad 初始化 每次都将文件信息读到类中
        Storage 数据持久化
        增删查改
*/

#ifndef __M_DATAMANAGER_H__
#define __M_DATAMANAGER_H__
#include<unordered_map>
#include<pthread.h>
#include<thread>
#include"Cutil.hpp"
#include"Config.hpp"

namespace Hxy_Cloud
{
    //数据信息结构体
    typedef struct  BackUpInfo_t
    {
        BackUpInfo_t(){}
        BackUpInfo_t(const std::string& realpath)
        {
            Hxy_Cloud::FileUtil fu(realpath);
            if(fu.Exists() == false)
            {
                CloudLog::GetInstance().Fatal(__FILE__,__LINE__,"文件不存在");
                assert(fu.Exists());
            }
            Hxy_Cloud::Config* conf = Hxy_Cloud::Config::GetInstance();
            std::string packpath = conf->GetPackDir();
            std::string packsuffix = conf->GetPackFileSuf();
            std::string download = conf->GetDownloadPer();

            size = fu.FileSize();
            atime = fu.LastATime();
            mtime = fu.LastMTime();
            is_pack = false;
            real_path = realpath;
            // ./abc/abc/test.txt  ->  ./abc/abc/test.txt.lz
            pack_path = packpath + fu.FileName() + packsuffix;
            // ./donwloads/test.txt
            url_path = download + fu.FileName();
        }
        size_t size;   //文件大小
        time_t atime;  //文件最近访问时间
        time_t mtime;  //文件最新修改时间
        bool is_pack;  //是否压缩标志
        std::string real_path; //文件实际存储路径
        std::string pack_path; //压缩包存储路径
        std::string url_path; //文件访问url路径
    }BackUpInfo;

    //数据管理实现
    class DataManager
    {
        public:
        DataManager()
        {
            _backup_path = Hxy_Cloud::Config::GetInstance()->GetBackupFile();
            pthread_rwlock_init(&_rwlock,nullptr);
            InitLoad();
        }
        ~DataManager()
        {
            pthread_rwlock_destroy(&_rwlock);
        }
        //初始化数据存储文件
        bool InitLoad()
        {
            //1.读取数据将数据反序列化
            Hxy_Cloud::FileUtil fu(_backup_path);
            if(fu.Exists() == false)
            {
                CloudLog::GetInstance().Info(__FILE__,__LINE__,"不存在_backup_path路径");
                return true;
            }
            std::string body;
            if(fu.GetContent(&body) == false)
            {
                CloudLog::GetInstance().Fatal(__FILE__,__LINE__,"数据读取失败");
                return false;
            }
            Json::Value root;
            if(Hxy_Cloud::JsonUtil::Deserialization(body,&root) == false)
            {
                CloudLog::GetInstance().Fatal(__FILE__,__LINE__,"反序列化失败");
                return false;
            }
            //2.提取反序列化的数据
            for(int i = 0;i<root.size();i++)
            {
                BackUpInfo info;
                info.is_pack = root[i]["is_pack"].asBool();
                info.atime = root[i]["atime"].asInt64();
                info.mtime = root[i]["mtime"].asInt64();
                info.size = root[i]["size"].asInt64();
                info.real_path = root[i]["real_path"].asString();
                info.pack_path = root[i]["pack_path"].asString();
                info.url_path = root[i]["url_path"].asString();
                //3.将数据插入到table中
                Insert(info);
            }
            return true;
        }
        //数据持久化存储
        bool Storage()
        {
            //1.获取数据
            std::vector<BackUpInfo> infos;
            GetAll(&infos);
            //2.将数据转化为json::value格式
            Json::Value roots;  //存放所有info数据
            for(auto i : infos)
            {
                Json::Value root;
                root["is_pack"] = i.is_pack;
                root["size"] = (Json::Int64)i.size;
                root["atime"] = (Json::Int64)i.atime;
                root["mtime"] = (Json::Int64)i.mtime;
                root["pack_path"] = i.pack_path;
                root["real_path"] = i.real_path;
                root["url_path"] = i.url_path;
                roots.append(root);
            }
            //3.进行序列化
            std::string ser;
            if(Hxy_Cloud::JsonUtil::Serializable(roots,&ser) == false)
            {
                CloudLog::GetInstance().Fatal(__FILE__,__LINE__,"序列化失败");
                return false;
            }
            //4.写入存储文件
            Hxy_Cloud::FileUtil fu(_backup_path);
            if(fu.SetContent(ser) == false)
            {
                CloudLog::GetInstance().Fatal(__FILE__,__LINE__,"数据写入失败");
                return false;       
            }
            return true;
        }
        //将BackUpInfo数据插入表中
        bool Insert(const BackUpInfo& val)
        {
            pthread_rwlock_wrlock(&_rwlock);
            _table[val.url_path] = val;
            pthread_rwlock_unlock(&_rwlock);
            std::cout<<"Insertsize : "<<_table.size()<<std::endl;
            Storage();
            return true;
        }
        //更新数据
        bool Update(const BackUpInfo& val){
            pthread_rwlock_wrlock(&_rwlock);
            _table[val.url_path] = val;
            pthread_rwlock_unlock(&_rwlock);
            Storage();
            return true;
        }
        //通过url获取BackUpInfo
        bool GetOneByUrl(const std::string& url,BackUpInfo* val){
            pthread_rwlock_wrlock(&_rwlock);
            auto it = _table.find(url);
            if(it == _table.end())
            {
                CloudLog::GetInstance().Fatal(__FILE__,__LINE__,"未在表内找到文件");
                pthread_rwlock_unlock(&_rwlock);
                return false;
            }
            *val = it->second;
            pthread_rwlock_unlock(&_rwlock);
            return true;
        }
        //通过realpath获取BackUpInfo
        bool GetOnrByRealPath(const std::string& realpath,BackUpInfo* val){
            pthread_rwlock_wrlock(&_rwlock);
            auto it = _table.begin();
            for(;it != _table.end();++it)
            {
                if(it->second.real_path == realpath)
                {
                    *val = it->second;
                    pthread_rwlock_unlock(&_rwlock);
                    return true;
                }
            }
            pthread_rwlock_unlock(&_rwlock);
            return false;
        }
        //获取表中所有数据
        bool GetAll(std::vector<BackUpInfo> * arry){
            pthread_rwlock_wrlock(&_rwlock);
            std::cout<<"GetAllsize : "<<_table.size()<<std::endl;
            for(auto [f,s] : _table)
            {
                arry->push_back(s);
            }
            pthread_rwlock_unlock(&_rwlock);
            return true;
        }
        private:
        std::string _backup_path;    //文件操作对象
        std::unordered_map<std::string,BackUpInfo> _table;  //文件访问url和数据结构体映射表
        pthread_rwlock_t _rwlock;   //读写锁
        std::thread _thread;
    };
}

#endif